package uk.me.dewi.appenin.android.dao.db.sqlite;

import uk.me.dewi.appenin.android.dao.PersonDao;
import uk.me.dewi.appenin.android.entity.Person;
import uk.me.dewi.util.DataAccessException;
import android.content.ContentValues;
import android.content.Context;
import android.database.Cursor;
import android.database.SQLException;
import android.database.sqlite.SQLiteDatabase;

public class PersonSqliteDao implements PersonDao{
    private static final String DATABASE_TABLE = "persons";
    public static final String KEY_NAME = "name";
    public static final String KEY_EMAIL = "email";
    public static final String KEY_ROWID = "_id";

    private DatabaseHelper mDbHelper;
    private SQLiteDatabase mDb;
    
    private final Context mCtx;
    
    public PersonSqliteDao(Context ctx){
        this.mCtx = ctx;
        this.open();
    }

    /**
     * Open the persons database. If it cannot be opened, try to create a new
     * instance of the database. If it cannot be created, throw an exception to
     * signal the failure
     * 
     * @return this (self reference, allowing this to be chained in an
     *         initialization call)
     * @throws SQLException if the database could be neither opened or created
     */
    public PersonSqliteDao open() throws SQLException {
        mDbHelper = new DatabaseHelper(mCtx);
        mDb = mDbHelper.getWritableDatabase();
        return this;
    }
    
    public void close() {
        mDbHelper.close();
    }
    
    @Override
    public Person createPerson(Person person) throws DataAccessException{
        try{
            ContentValues initialValues = new ContentValues();
            initialValues.put(KEY_NAME, person.mName);
            initialValues.put(KEY_EMAIL, person.mEmail);
    
            person.mId = mDb.insert(DATABASE_TABLE, null, initialValues);
            return person;
        }catch(SQLException e){
            throw new DataAccessException("Failed to open SQLite database", e);
        }
    }
    
    @Override
    public boolean deletePerson(long rowId) throws DataAccessException{
        try{
            return mDb.delete(DATABASE_TABLE, KEY_ROWID + "=" + rowId, null) > 0;
        }catch(SQLException e){
            throw new DataAccessException("Failed to open SQLite database", e);
        }
    }
    
    public Person fetchPerson(long rowId) throws DataAccessException {
        Cursor cursor = null;
        try{
            cursor =  mDb.query(true, DATABASE_TABLE, new String[] {KEY_ROWID,
                                KEY_NAME, KEY_EMAIL}, KEY_ROWID + "=" + rowId, null,
                                null, null, null, null);
            if (cursor != null) {
                cursor.moveToFirst();
            }
            
            Person person = new Person();
            person.mName = cursor.getString(
                    cursor.getColumnIndexOrThrow(PersonSqliteDao.KEY_NAME));
            person.mEmail = cursor.getString(
                    cursor.getColumnIndexOrThrow(PersonSqliteDao.KEY_EMAIL));
            return person;
        }catch(SQLException e){
            throw new DataAccessException("Could not fetch persion with ID "+rowId, e);
        }finally{
            if(cursor != null && !cursor.isClosed()){
                cursor.close();
            }
        }
    }
    
    @Override
    public boolean updatePerson(Person person) throws DataAccessException{
        try{
            ContentValues args = new ContentValues();
            args.put(KEY_NAME, person.mName);
            args.put(KEY_EMAIL, person.mEmail);
    
            return mDb.update(DATABASE_TABLE, args, KEY_ROWID + "=" + person.mId, null) > 0;
        }catch(SQLException e){
            throw new DataAccessException("Failed to open SQLite database", e);
        }
    }
}
